home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / lysrc.zip / LEXBASE.PAS < prev    next >
Pascal/Delphi Source File  |  1993-01-24  |  32KB  |  1,130 lines

  1.  
  2. unit LexBase;
  3.  
  4. (* 2-5-91 AG *)
  5.  
  6. (* Copyright (c) 1990,91 by Albert Graef, Schillerstr. 18,
  7.    6509 Schornsheim/Germany
  8.    All rights reserved *)
  9.  
  10. interface
  11.  
  12. (* This module collects the basic data types and operations used in the TP
  13.    Lex program, and other basic stuff that does not belong anywhere else:
  14.    - Lex input and output files and corresponding bookkeeping information
  15.      used by the parser
  16.    - symbolic character constants
  17.    - dynamically allocated strings and character classes
  18.    - integer sets
  19.    - generic quicksort and hash table routines
  20.    - utilities for list-generating
  21.    - other tiny utilities *)
  22.  
  23. const
  24.  
  25. (* symbolic character constants: *)
  26.  
  27. bs   = #8;    (* backspace character *)
  28. tab  = #9;    (* tab character *)
  29. nl   = #10;    (* newline character *)
  30. cr   = #13;    (* carriage return *)
  31. ff   = #12;    (* form feed character *)
  32.  
  33. var
  34.  
  35. (* Filenames: *)
  36.  
  37. lfilename     : String;
  38. pasfilename   : String;
  39. lstfilename   : String;
  40. codfilename   : String;
  41.  
  42. (* Lex input, output, list and code template file: *)
  43.  
  44. yyin, yylst, yyout, yycod : Text;
  45.  
  46. (* the following values are initialized and updated by the parser: *)
  47.  
  48. line : String;  (* current input line *)
  49. lno  : Integer; (* current line number *)
  50.  
  51. const
  52.  
  53. max_elems  = 100;  (* maximum size of integer sets *)
  54.  
  55. type
  56.  
  57. (* String and character class pointers: *)
  58.  
  59. StrPtr    = ^String;
  60. CClass    = set of Char;
  61. CClassPtr = ^CClass;
  62.  
  63. (* Sorted integer sets: *)
  64.  
  65. IntSet    = array [0..max_elems] of Integer;
  66.               (* word 0 is size *)
  67. IntSetPtr = ^IntSet;
  68.  
  69. (* Regular expressions: *)
  70.  
  71. RegExpr = ^Node;
  72.  
  73. NodeType = (mark_node,    (* marker node *)
  74.             char_node,    (* character node *)
  75.             str_node,     (* string node *)
  76.             cclass_node,  (* character class node *)
  77.             star_node,    (* star node *)
  78.             plus_node,    (* plus node *)
  79.             opt_node,     (* option node *)
  80.             cat_node,     (* concatenation node *)
  81.             alt_node);    (* alternatives node (|) *)
  82.  
  83. Node = record case node_type : NodeType of
  84.          mark_node : (rule, pos : Integer);
  85.          char_node : (c : Char);
  86.          str_node : (str : StrPtr);
  87.          cclass_node : (cc : CClassPtr);
  88.          star_node, plus_node, opt_node : (r : RegExpr);
  89.          cat_node, alt_node : (r1, r2 : RegExpr);
  90.        end;
  91.  
  92. (* Some standard character classes: *)
  93.  
  94. const
  95.  
  96. letters   : CClass = ['A'..'Z','a'..'z','_'];
  97. digits    : CClass = ['0'..'9'];
  98. alphanums : CClass = ['A'..'Z','a'..'z','_','0'..'9'];
  99.  
  100. (* Operations: *)
  101.  
  102. (* Strings and character classes: *)
  103.  
  104. function newStr(str : String) : StrPtr;
  105.   (* creates a string pointer (only the space actually needed for the given
  106.      string is allocated) *)
  107. function newCClass(cc : CClass) : CClassPtr;
  108.   (* creates a CClass pointer *)
  109.  
  110. (* Integer sets (set arguments are passed by reference even if they are not
  111.    modified, for greater efficiency): *)
  112.  
  113. procedure empty(var M : IntSet);
  114.   (* initializes M as empty *)
  115. procedure singleton(var M : IntSet; i : Integer);
  116.   (* initializes M as a singleton set containing the element i *)
  117. procedure include(var M : IntSet; i : Integer);
  118.   (* include i in M *)
  119. procedure exclude(var M : IntSet; i : Integer);
  120.   (* exclude i from M *)
  121. procedure setunion(var M, N : IntSet);
  122.   (* adds N to M *)
  123. procedure setminus(var M, N : IntSet);
  124.   (* removes N from M *)
  125. procedure intersect(var M, N : IntSet);
  126.   (* removes from M all elements NOT in N *)
  127. function size(var M : IntSet) : Integer;
  128.   (* cardinality of set M *)
  129. function member(i : Integer; var M : IntSet) : Boolean;
  130.   (* tests for membership of i in M *)
  131. function isempty(var M : IntSet) : Boolean;
  132.   (* checks whether M is an empty set *)
  133. function equal(var M, N : IntSet) : Boolean;
  134.   (* checks whether M and N are equal *)
  135. function subseteq(var M, N : IntSet) : Boolean;
  136.   (* checks whether M is a subset of N *)
  137. function newIntSet : IntSetPtr;
  138.   (* creates a pointer to an empty integer set *)
  139.  
  140. (* Constructors for regular expressions: *)
  141.  
  142. const epsExpr : RegExpr = nil;
  143.   (* empty regular expression *)
  144. function markExpr(rule, pos : Integer) : RegExpr;
  145.   (* markers are used to denote endmarkers of rules, as well as other
  146.      special positions in rules, e.g. the position of the lookahead
  147.      operator; they are considered nullable; by convention, we use
  148.      the following pos numbers:
  149.      - 0: endmarker position
  150.      - 1: lookahead operator position *)
  151. function charExpr(c : Char) : RegExpr;
  152.   (* character c *)
  153. function strExpr(str : StrPtr) : RegExpr;
  154.   (* "str" *)
  155. function cclassExpr(cc : CClassPtr) : RegExpr;
  156.   (* [str] where str are the literals in cc *)
  157. function starExpr(r : RegExpr) : RegExpr;
  158.   (* r* *)
  159. function plusExpr(r : RegExpr) : RegExpr;
  160.   (* r+ *)
  161. function optExpr(r : RegExpr) : RegExpr;
  162.   (* r? *)
  163. function mnExpr(r : RegExpr; m, n : Integer) : RegExpr;
  164.   (* constructor expanding expression r{m,n} to the corresponding
  165.      alt expression r^m|...|r^n *)
  166. function catExpr(r1, r2 : RegExpr) : RegExpr;
  167.   (* r1r2 *)
  168. function altExpr(r1, r2 : RegExpr) : RegExpr;
  169.   (* r1|r2 *)
  170.  
  171. (* Unifiers for regular expressions:
  172.    The following predicates check whether the specified regular
  173.    expression r is of the denoted type; if the predicate succeeds,
  174.    the other arguments of the predicate are instantiated to the
  175.    corresponding values. *)
  176.  
  177. function is_epsExpr(r : RegExpr) : Boolean;
  178.   (* empty regular expression *)
  179. function is_markExpr(r : RegExpr; var rule, pos : Integer) : Boolean;
  180.   (* marker expression *)
  181. function is_charExpr(r : RegExpr; var c : Char) : Boolean;
  182.   (* character c *)
  183. function is_strExpr(r : RegExpr; var str : StrPtr) : Boolean;
  184.   (* "str" *)
  185. function is_cclassExpr(r : RegExpr; var cc : CClassPtr) : Boolean;
  186.   (* [str] where str are the literals in cc *)
  187. function is_starExpr(r : RegExpr; var r1 : RegExpr) : Boolean;
  188.   (* r1* *)
  189. function is_plusExpr(r : RegExpr; var r1 : RegExpr) : Boolean;
  190.   (* r1+ *)
  191. function is_optExpr(r : RegExpr; var r1 : RegExpr) : Boolean;
  192.   (* r1? *)
  193. function is_catExpr(r : RegExpr; var r1, r2 : RegExpr) : Boolean;
  194.   (* r1r2 *)
  195. function is_altExpr(r : RegExpr; var r1, r2 : RegExpr) : Boolean;
  196.   (* r1|r2 *)
  197.  
  198. (* Quicksort: *)
  199.  
  200. type
  201.  
  202. OrderPredicate = function (i, j : Integer) : Boolean;
  203. SwapProc = procedure (i, j : Integer);
  204.  
  205. procedure quicksort(lo, hi: Integer;
  206.                     less : OrderPredicate;
  207.                     swap : SwapProc);
  208.   (* General inplace sorting procedure based on the quicksort algorithm.
  209.      This procedure can be applied to any sequential data structure;
  210.      only the corresponding routines less which compares, and swap which
  211.      swaps two elements i,j of the target data structure, must be
  212.      supplied as appropriate for the target data structure.
  213.      - lo, hi: the lower and higher indices, indicating the elements to
  214.        be sorted
  215.      - less(i, j): should return true if element no. i `is less than'
  216.        element no. j, and false otherwise; any total quasi-ordering may
  217.        be supplied here (if neither less(i, j) nor less(j, i) then elements
  218.        i and j are assumed to be `equal').
  219.      - swap(i, j): should swap the elements with index i and j *)
  220.  
  221. (* Generic hash table routines (based on quadratic rehashing; hence the
  222.    table size must be a prime number): *)
  223.  
  224. type
  225.  
  226. TableLookupProc = function(k : Integer) : String;
  227. TableEntryProc  = procedure(k : Integer; symbol : String);
  228.  
  229. function key(symbol : String;
  230.              table_size : Integer;
  231.              lookup : TableLookupProc;
  232.              entry  : TableEntryProc) : Integer;
  233.   (* returns a hash table key for symbol; inserts the symbol into the
  234.      table if necessary
  235.      - table_size is the symbol table size and must be a fixed prime number
  236.      - lookup is the table lookup procedure which should return the string
  237.        at key k in the table ('' if entry is empty)
  238.      - entry is the table entry procedure which is assumed to store the
  239.        given symbol at the given location *)
  240.  
  241. function definedKey(symbol : String;
  242.                     table_size : Integer;
  243.                     lookup : TableLookupProc) : Boolean;
  244.   (* checks the table to see if symbol is in the table *)
  245.  
  246. (* Utility routines: *)
  247.  
  248. function min(i, j : Integer) : Integer;
  249. function max(i, j : Integer) : Integer;
  250.   (* minimum and maximum of two integers *)
  251. function nchars(cc : CClass) : Integer;
  252.   (* returns the cardinality (number of characters) of a character class *)
  253. function upper(str : String) : String;
  254.   (* returns str converted to uppercase *)
  255. function strip(str : String) : String;
  256.   (* returns str with leading and trailing blanks stripped off *)
  257. function blankStr(str : String) : String;
  258.   (* returns string of same length as str, with all non-whitespace characters
  259.      replaced by blanks *)
  260. function intStr(i : Integer) : String;
  261.   (* returns the string representation of i *)
  262. function isInt(str : String; var i : Integer) : Boolean;
  263.   (* checks whether str represents an integer; if so, returns the
  264.      value of it in i *)
  265. function path(filename : String) : String;
  266.   (* returns the path in filename *)
  267. function root(filename : String) : String;
  268.   (* returns root (i.e. extension stripped from filename) of
  269.      filename *)
  270. function addExt(filename, ext : String) : String;
  271.   (* if filename has no extension and last filename character is not '.',
  272.      add extension ext to filename *)
  273. function file_size(filename : String) : LongInt;
  274.   (* determines file size in bytes *)
  275.  
  276. (* Utility functions for list generating routines: *)
  277.  
  278. function charStr(c : char; reserved : CClass) : String;
  279.   (* returns a print name for character c, using the standard escape
  280.      conventions; reserved is the class of `reserved' special characters
  281.      which should be quoted with \ (\ itself is always quoted) *)
  282. function singleQuoteStr(str : String) : String;
  283.   (* returns print name of str enclosed in single quotes, using the
  284.      standard escape conventions *)
  285. function doubleQuoteStr(str : String) : String;
  286.   (* returns print name of str enclosed in double quotes, using the
  287.      standard escape conventions *)
  288. function cclassStr(cc : CClass) : String;
  289.   (* returns print name of character class cc, using the standard escape
  290.      conventions; if cc contains more than 128 elements, the complement
  291.      notation (^) is used; if cc is the class of all (non-null) characters
  292.      except newline, the period notation is used *)
  293. function cclassOrCharStr(cc : CClass) : String;
  294.   (* returns a print name for character class cc (either cclassStr, or,
  295.      if cc contains only one element, character in single quotes) *)
  296. function regExprStr(r : RegExpr) : String;
  297.   (* unparses a regular expression *)
  298.  
  299. implementation
  300.  
  301. uses LexMsgs;
  302.  
  303. (* String and character class pointers: *)
  304.  
  305. function newStr(str : String) : StrPtr;
  306.   var strp : StrPtr;
  307.   begin
  308.     getmem(strp, succ(length(str)));
  309.     move(str, strp^, succ(length(str)));
  310.     newStr := strp;
  311.   end(*newStr*);
  312.  
  313. function newCClass(cc : CClass) : CClassPtr;
  314.   var ccp : CClassPtr;
  315.   begin
  316.     new(ccp);
  317.     ccp^ := cc;
  318.     newCClass := ccp;
  319.   end(*newCClass*);
  320.  
  321. (* Integer sets: *)
  322.  
  323. procedure empty(var M : IntSet);
  324.   begin
  325.     M[0] := 0;
  326.   end(*empty*);
  327.  
  328. procedure singleton(var M : IntSet; i : Integer);
  329.   begin
  330.     M[0] := 1; M[1] := i;
  331.   end(*singleton*);
  332.  
  333. procedure include(var M : IntSet; i : Integer);
  334.   var l, r, k : Integer;
  335.   begin
  336.     (* binary search: *)
  337.     l := 1; r := M[0];
  338.     k := l + (r-l) div 2;
  339.     while (l<r) and (M[k]<>i) do
  340.       begin
  341.         if M[k]<i then
  342.           l := succ(k)
  343.         else
  344.           r := pred(k);
  345.         k := l + (r-l) div 2;
  346.       end;
  347.     if (k>M[0]) or (M[k]<>i) then
  348.       begin
  349.         if M[0]>=max_elems then fatal(intset_overflow);
  350.         if (k<=M[0]) and (M[k]<i) then
  351.           begin
  352.             move(M[k+1], M[k+2], (M[0]-k)*sizeOf(Integer));
  353.             M[k+1] := i;
  354.           end
  355.         else
  356.           begin
  357.             move(M[k], M[k+1], (M[0]-k+1)*sizeOf(Integer));
  358.             M[k] := i;
  359.           end;
  360.         inc(M[0]);
  361.       end;
  362.   end(*include*);
  363.  
  364. procedure exclude(var M : IntSet; i : Integer);
  365.   var l, r, k : Integer;
  366.   begin
  367.     (* binary search: *)
  368.     l := 1; r := M[0];
  369.     k := l + (r-l) div 2;
  370.     while (l<r) and (M[k]<>i) do
  371.       begin
  372.         if M[k]<i then
  373.           l := succ(k)
  374.         else
  375.           r := pred(k);
  376.         k := l + (r-l) div 2;
  377.       end;
  378.     if (k<=M[0]) and (M[k]=i) then
  379.       begin
  380.         move(M[k+1], M[k], (M[0]-k)*sizeOf(Integer));
  381.         dec(M[0]);
  382.       end;
  383.   end(*exclude*);
  384.  
  385. procedure setunion(var M, N : IntSet);
  386.   var
  387.     K : IntSet;
  388.     i, j, i_M, i_N : Integer;
  389.   begin
  390.     (* merge sort: *)
  391.     i := 0; i_M := 1; i_N := 1;
  392.     while (i_M<=M[0]) and (i_N<=N[0]) do
  393.       begin
  394.         inc(i);
  395.         if i>max_elems then fatal(intset_overflow);
  396.         if M[i_M]<N[i_N] then
  397.           begin
  398.             K[i] := M[i_M]; inc(i_M);
  399.           end
  400.         else if N[i_N]<M[i_M] then
  401.           begin
  402.             K[i] := N[i_N]; inc(i_N);
  403.           end
  404.         else
  405.           begin
  406.             K[i] := M[i_M]; inc(i_M); inc(i_N);
  407.           end
  408.       end;
  409.     for j := i_M to M[0] do
  410.       begin
  411.         inc(i);
  412.         if i>max_elems then fatal(intset_overflow);
  413.         K[i] := M[j];
  414.       end;
  415.     for j := i_N to N[0] do
  416.       begin
  417.         inc(i);
  418.         if i>max_elems then fatal(intset_overflow);
  419.         K[i] := N[j];
  420.       end;
  421.     K[0] := i;
  422.     move(K, M, succ(i)*sizeOf(Integer));
  423.   end(*setunion*);
  424.  
  425. procedure setminus(var M, N : IntSet);
  426.   var
  427.     K : IntSet;
  428.     i, i_M, i_N : Integer;
  429.   begin
  430.     i := 0; i_N := 1;
  431.     for i_M := 1 to M[0] do
  432.       begin
  433.         while (i_N<=N[0]) and (N[i_N]<M[i_M]) do inc(i_N);
  434.         if (i_N>N[0]) or (N[i_N]>M[i_M]) then
  435.           begin
  436.             inc(i);
  437.             K[i] := M[i_M];
  438.           end
  439.         else
  440.           inc(i_N);
  441.       end;
  442.     K[0] := i;
  443.     move(K, M, succ(i)*sizeOf(Integer));
  444.   end(*setminus*);
  445.  
  446. procedure intersect(var M, N : IntSet);
  447.   var
  448.     K : IntSet;
  449.     i, i_M, i_N : Integer;
  450.   begin
  451.     i := 0; i_N := 1;
  452.     for i_M := 1 to M[0] do
  453.       begin
  454.         while (i_N<=N[0]) and (N[i_N]<M[i_M]) do inc(i_N);
  455.         if (i_N<=N[0]) and (N[i_N]=M[i_M]) then
  456.           begin
  457.             inc(i);
  458.             K[i] := M[i_M];
  459.             inc(i_N);
  460.           end
  461.       end;
  462.     K[0] := i;
  463.     move(K, M, succ(i)*sizeOf(Integer));
  464.   end(*intersect*);
  465.  
  466. function size(var M : IntSet) : Integer;
  467.   begin
  468.     size := M[0]
  469.   end(*size*);
  470.  
  471. function member(i : Integer; var M : IntSet) : Boolean;
  472.   var l, r, k : Integer;
  473.   begin
  474.     (* binary search: *)
  475.     l := 1; r := M[0];
  476.     k := l + (r-l) div 2;
  477.     while (l<r) and (M[k]<>i) do
  478.       begin
  479.         if M[k]<i then
  480.           l := succ(k)
  481.         else
  482.           r := pred(k);
  483.         k := l + (r-l) div 2;
  484.       end;
  485.     member := (k<=M[0]) and (M[k]=i);
  486.   end(*member*);
  487.  
  488. function isempty(var M : IntSet) : Boolean;
  489.   begin
  490.     isempty := M[0]=0
  491.   end(*isempty*);
  492.  
  493. function equal(var M, N : IntSet) : Boolean;
  494.   var i : Integer;
  495.   begin
  496.     if M[0]<>N[0] then
  497.       equal := false
  498.     else
  499.       begin
  500.         for i := 1 to M[0] do
  501.           if M[i]<>N[i] then
  502.             begin
  503.               equal := false;
  504.               exit
  505.             end;
  506.         equal := true
  507.       end
  508.   end(*equal*);
  509.  
  510. function subseteq(var M, N : IntSet) : Boolean;
  511.   var
  512.     i_M, i_N : Integer;
  513.   begin
  514.     if M[0]>N[0] then
  515.       subseteq := false
  516.     else
  517.       begin
  518.         i_N := 1;
  519.         for i_M := 1 to M[0] do
  520.           begin
  521.             while (i_N<=N[0]) and (N[i_N]<M[i_M]) do inc(i_N);
  522.             if (i_N>N[0]) or (N[i_N]>M[i_M]) then
  523.               begin
  524.                 subseteq := false;
  525.                 exit
  526.               end
  527.             else
  528.               inc(i_N);
  529.           end;
  530.         subseteq := true
  531.       end;
  532.   end(*subseteq*);
  533.  
  534. function newIntSet : IntSetPtr;
  535.   var
  536.     MP : IntSetPtr;
  537.   begin
  538.     getmem(MP, (max_elems+1)*sizeOf(Integer));
  539.     MP^[0] := 0;
  540.     newIntSet := MP
  541.   end(*newIntSet*);
  542.  
  543. (* Constructors for regular expressions: *)
  544.  
  545. function newExpr(node_type : NodeType; n : Integer) : RegExpr;
  546.   (* returns new RegExpr node (n: number of bytes to allocate) *)
  547.   var x : RegExpr;
  548.   begin
  549.     getmem(x, sizeOf(NodeType)+n);
  550.     x^.node_type := node_type;
  551.     newExpr := x
  552.   end(*newExpr*);
  553. function markExpr(rule, pos : Integer) : RegExpr;
  554.   var x : RegExpr;
  555.   begin
  556.     x := newExpr(mark_node, 2*sizeOf(Integer));
  557.     x^.rule := rule;
  558.     x^.pos  := pos;
  559.     markExpr := x
  560.   end(*markExpr*);
  561. function charExpr(c : Char) : RegExpr;
  562.   var x : RegExpr;
  563.   begin
  564.     x := newExpr(char_node, sizeOf(Char));
  565.     x^.c := c;
  566.     charExpr := x
  567.   end(*charExpr*);
  568. function strExpr(str : StrPtr) : RegExpr;
  569.   var x : RegExpr;
  570.   begin
  571.     x := newExpr(str_node, sizeOf(StrPtr));
  572.     x^.str := str;
  573.     strExpr := x
  574.   end(*strExpr*);
  575. function cclassExpr(cc : CClassPtr) : RegExpr;
  576.   var x : RegExpr;
  577.   begin
  578.     x := newExpr(cclass_node, sizeOf(CClassPtr));
  579.     x^.cc := cc;
  580.     cclassExpr := x
  581.   end(*cclassExpr*);
  582. function starExpr(r : RegExpr) : RegExpr;
  583.   var x : RegExpr;
  584.   begin
  585.     x := newExpr(star_node, sizeOf(RegExpr));
  586.     x^.r := r;
  587.     starExpr := x
  588.   end(*starExpr*);
  589. function plusExpr(r : RegExpr) : RegExpr;
  590.   var x : RegExpr;
  591.   begin
  592.     x := newExpr(plus_node, sizeOf(RegExpr));
  593.     x^.r := r;
  594.     plusExpr := x
  595.   end(*plusExpr*);
  596. function optExpr(r : RegExpr) : RegExpr;
  597.   var x : RegExpr;
  598.   begin
  599.     x := newExpr(opt_node, sizeOf(RegExpr));
  600.     x^.r := r;
  601.     optExpr := x
  602.   end(*optExpr*);
  603. function mnExpr(r : RegExpr; m, n : Integer) : RegExpr;
  604.   var
  605.     ri, rmn : RegExpr;
  606.     i : Integer;
  607.   begin
  608.     if (m>n) or (n=0) then
  609.       mnExpr := epsExpr
  610.     else
  611.       begin
  612.         (* construct r^m: *)
  613.         if m=0 then
  614.           ri := epsExpr
  615.         else
  616.           begin
  617.             ri := r;
  618.             for i := 2 to m do
  619.               ri := catExpr(ri, r);
  620.           end;
  621.         (* construct r{m,n}: *)
  622.         rmn := ri;                  (* r{m,n} := r^m *)
  623.         for i := m+1 to n do
  624.           begin
  625.             if is_epsExpr(ri) then
  626.               ri := r
  627.             else
  628.               ri := catExpr(ri, r);
  629.             rmn := altExpr(rmn, ri)  (* r{m,n} := r{m,n} | r^i,
  630.                                         i=m+1,...,n *)
  631.           end;
  632.         mnExpr := rmn
  633.       end
  634.   end(*mnExpr*);
  635. function catExpr(r1, r2 : RegExpr) : RegExpr;
  636.   var x : RegExpr;
  637.   begin
  638.     x := newExpr(cat_node, 2*sizeOf(RegExpr));
  639.     x^.r1 := r1;
  640.     x^.r2 := r2;
  641.     catExpr := x
  642.   end(*catExpr*);
  643. function altExpr(r1, r2 : RegExpr) : RegExpr;
  644.   var x : RegExpr;
  645.   begin
  646.     x := newExpr(alt_node, 2*sizeOf(RegExpr));
  647.     x^.r1 := r1;
  648.     x^.r2 := r2;
  649.     altExpr := x
  650.   end(*altExpr*);
  651.  
  652. (* Unifiers for regular expressions: *)
  653.  
  654. function is_epsExpr(r : RegExpr) : Boolean;
  655.   begin
  656.     is_epsExpr := r=epsExpr
  657.   end(*is_epsExpr*);
  658. function is_markExpr(r : RegExpr; var rule, pos : Integer) : Boolean;
  659.   begin
  660.     if r=epsExpr then
  661.       is_markExpr := false
  662.     else if r^.node_type=mark_node then
  663.       begin
  664.         is_markExpr := true;
  665.         rule := r^.rule;
  666.         pos  := r^.pos;
  667.       end
  668.     else
  669.       is_markExpr := false
  670.   end(*is_markExpr*);
  671. function is_charExpr(r : RegExpr; var c : Char) : Boolean;
  672.   begin
  673.     if r=epsExpr then
  674.       is_charExpr := false
  675.     else if r^.node_type=char_node then
  676.       begin
  677.         is_charExpr := true;
  678.         c := r^.c
  679.       end
  680.     else
  681.       is_charExpr := false
  682.   end(*is_charExpr*);
  683. function is_strExpr(r : RegExpr; var str : StrPtr) : Boolean;
  684.   begin
  685.     if r=epsExpr then
  686.       is_strExpr := false
  687.     else if r^.node_type=str_node then
  688.       begin
  689.         is_strExpr := true;
  690.         str := r^.str;
  691.       end
  692.     else
  693.       is_strExpr := false
  694.   end(*is_strExpr*);
  695. function is_cclassExpr(r : RegExpr; var cc : CClassPtr) : Boolean;
  696.   begin
  697.     if r=epsExpr then
  698.       is_cclassExpr := false
  699.     else if r^.node_type=cclass_node then
  700.       begin
  701.         is_cclassExpr := true;
  702.         cc := r^.cc
  703.       end
  704.     else
  705.       is_cclassExpr := false
  706.   end(*is_cclassExpr*);
  707. function is_starExpr(r : RegExpr; var r1 : RegExpr) : Boolean;
  708.   begin
  709.     if r=epsExpr then
  710.       is_starExpr := false
  711.     else if r^.node_type=star_node then
  712.       begin
  713.         is_starExpr := true;
  714.         r1 := r^.r
  715.       end
  716.     else
  717.       is_starExpr := false
  718.   end(*is_starExpr*);
  719. function is_plusExpr(r : RegExpr; var r1 : RegExpr) : Boolean;
  720.   begin
  721.     if r=epsExpr then
  722.       is_plusExpr := false
  723.     else if r^.node_type=plus_node then
  724.       begin
  725.         is_plusExpr := true;
  726.         r1 := r^.r
  727.       end
  728.     else
  729.       is_plusExpr := false
  730.   end(*is_plusExpr*);
  731. function is_optExpr(r : RegExpr; var r1 : RegExpr) : Boolean;
  732.   begin
  733.     if r=epsExpr then
  734.       is_optExpr := false
  735.     else if r^.node_type=opt_node then
  736.       begin
  737.         is_optExpr := true;
  738.         r1 := r^.r
  739.       end
  740.     else
  741.       is_optExpr := false
  742.   end(*is_optExpr*);
  743. function is_catExpr(r : RegExpr; var r1, r2 : RegExpr) : Boolean;
  744.   begin
  745.     if r=epsExpr then
  746.       is_catExpr := false
  747.     else if r^.node_type=cat_node then
  748.       begin
  749.         is_catExpr := true;
  750.         r1 := r^.r1;
  751.         r2 := r^.r2
  752.       end
  753.     else
  754.       is_catExpr := false
  755.   end(*is_catExpr*);
  756. function is_altExpr(r : RegExpr; var r1, r2 : RegExpr) : Boolean;
  757.   begin
  758.     if r=epsExpr then
  759.       is_altExpr := false
  760.     else if r^.node_type=alt_node then
  761.       begin
  762.         is_altExpr := true;
  763.         r1 := r^.r1;
  764.         r2 := r^.r2
  765.       end
  766.     else
  767.       is_altExpr := false
  768.   end(*is_altExpr*);
  769.  
  770. (* Quicksort: *)
  771.  
  772. procedure quicksort(lo, hi: Integer;
  773.                     less : OrderPredicate;
  774.                     swap : SwapProc);
  775.   (* derived from the quicksort routine in QSORT.PAS in the Turbo Pascal
  776.      distribution *)
  777.   procedure sort(l, r: Integer);
  778.     var i, j, k : Integer;
  779.     begin
  780.       i := l; j := r; k := (l+r) DIV 2;
  781.       repeat
  782.         while less(i, k) do inc(i);
  783.         while less(k, j) do dec(j);
  784.         if i<=j then
  785.           begin
  786.             swap(i, j);
  787.             if k=i then k := j (* pivot element swapped! *)
  788.             else if k=j then k := i;
  789.             inc(i); dec(j);
  790.           end;
  791.       until i>j;
  792.       if l<j then sort(l,j);
  793.       if i<r then sort(i,r);
  794.     end(*sort*);
  795.   begin
  796.     if lo<hi then sort(lo,hi);
  797.   end(*quicksort*);
  798.  
  799. (* Generic hash table routines: *)
  800.  
  801. function hash(str : String; table_size : Integer) : Integer;
  802.   (* computes a hash key for str *)
  803.   var i, key : Integer;
  804.   begin
  805.     key := 0;
  806.     for i := 1 to length(str) do
  807.       inc(key, ord(str[i]));
  808.     hash := key mod table_size + 1;
  809.   end(*hash*);
  810.  
  811. procedure newPos(var pos, incr, count : Integer; table_size : Integer);
  812.   (* computes a new position in the table (quadratic collision strategy)
  813.      - pos: current position (+inc)
  814.      - incr: current increment (+2)
  815.      - count: current number of collisions (+1)
  816.      quadratic collision formula for position of str after n collisions:
  817.        pos(str, n) = (hash(str)+n^2) mod table_size +1
  818.      note that n^2-(n-1)^2 = 2n-1 <=> n^2 = (n-1)^2 + (2n-1) for n>0,
  819.      i.e. the increment inc=2n-1 increments by two in each collision *)
  820.   begin
  821.     inc(count);
  822.     inc(pos, incr);
  823.     if pos>table_size then pos := pos mod table_size + 1;
  824.     inc(incr, 2)
  825.   end(*newPos*);
  826.  
  827. function key(symbol : String;
  828.              table_size : Integer;
  829.              lookup : TableLookupProc;
  830.              entry  : TableEntryProc) : Integer;
  831.   var pos, incr, count : Integer;
  832.   begin
  833.     pos := hash(symbol, table_size);
  834.     incr := 1;
  835.     count := 0;
  836.     while count<=table_size do
  837.       if lookup(pos)='' then
  838.         begin
  839.           entry(pos, symbol);
  840.           key := pos;
  841.           exit
  842.         end
  843.       else if lookup(pos)=symbol then
  844.         begin
  845.           key := pos;
  846.           exit
  847.         end
  848.       else
  849.         newPos(pos, incr, count, table_size);
  850.     fatal(sym_table_overflow)
  851.   end(*key*);
  852.  
  853. function definedKey(symbol : String;
  854.                     table_size : Integer;
  855.                     lookup : TableLookupProc) : Boolean;
  856.   var pos, incr, count : Integer;
  857.   begin
  858.     pos := hash(symbol, table_size);
  859.     incr := 1;
  860.     count := 0;
  861.     while count<=table_size do
  862.       if lookup(pos)='' then
  863.         begin
  864.           definedKey := false;
  865.           exit
  866.         end
  867.       else if lookup(pos)=symbol then
  868.         begin
  869.           definedKey := true;
  870.           exit
  871.         end
  872.       else
  873.         newPos(pos, incr, count, table_size);
  874.     definedKey := false
  875.   end(*definedKey*);
  876.  
  877. (* Utility routines: *)
  878.  
  879. function min(i, j : Integer) : Integer;
  880.   begin
  881.     if i<j then
  882.       min := i
  883.     else
  884.       min := j
  885.   end(*min*);
  886. function max(i, j : Integer) : Integer;
  887.   begin
  888.     if i>j then
  889.       max := i
  890.     else
  891.       max := j
  892.   end(*max*);
  893. function nchars(cc : CClass) : Integer;
  894.   var
  895.     c : Char;
  896.     count : Integer;
  897.   begin
  898.     count := 0;
  899.     for c := #0 to #255 do if c in cc then inc(count);
  900.     nchars := count;
  901.   end(*nchars*);
  902. function upper(str : String) : String;
  903.   var i : Integer;
  904.   begin
  905.     for i := 1 to length(str) do
  906.       str[i] := upCase(str[i]);
  907.     upper := str
  908.   end(*upper*);
  909. function strip(str : String) : String;
  910.   begin
  911.     while (length(str)>0) and ((str[1]=' ') or (str[1]=tab)) do
  912.       delete(str, 1, 1);
  913.     while (length(str)>0) and
  914.           ((str[length(str)]= ' ') or
  915.            (str[length(str)]=tab)) do
  916.       delete(str, length(str), 1);
  917.     strip := str;
  918.   end(*strip*);
  919. function blankStr(str : String) : String;
  920.   var i : Integer;
  921.   begin
  922.     for i := 1 to length(str) do
  923.       if str[i]<>tab then str[i] := ' ';
  924.     blankStr := str;
  925.   end(*blankStr*);
  926. function intStr(i : Integer) : String;
  927.   var s : String;
  928.   begin
  929.     str(i, s);
  930.     intStr := s
  931.   end(*intStr*);
  932. function isInt(str : String; var i : Integer) : Boolean;
  933.   var result : Integer;
  934.   begin
  935.     val(str, i, result);
  936.     isInt := result = 0;
  937.   end(*isInt*);
  938. function path(filename : String) : String;
  939.   var i : Integer;
  940.   begin
  941.     i := length(filename);
  942.     while (i>0) and (filename[i]<>'\') and (filename[i]<>':') do
  943.       dec(i);
  944.     path := copy(filename, 1, i);
  945.   end(*path*);
  946. function root(filename : String) : String;
  947.   var
  948.     i : Integer;
  949.   begin
  950.     root := filename;
  951.     for i := length(filename) downto 1 do
  952.       case filename[i] of
  953.         '.' :
  954.           begin
  955.             root := copy(filename, 1, i-1);
  956.             exit
  957.           end;
  958.         '\': exit;
  959.         else
  960.       end;
  961.   end(*addExt*);
  962. function addExt(filename, ext : String) : String;
  963.   (* implemented with goto for maximum efficiency *)
  964.   label x;
  965.   var
  966.     i : Integer;
  967.   begin
  968.     addExt := filename;
  969.     for i := length(filename) downto 1 do
  970.       case filename[i] of
  971.         '.' : exit;
  972.         '\': goto x;
  973.         else
  974.       end;
  975.     x : addExt := filename+'.'+ext
  976.   end(*addExt*);
  977. function file_size(filename : String) : LongInt;
  978.   var f : File;
  979.   begin
  980.     assign(f, filename);
  981.     reset(f, 1);
  982.     if ioresult=0 then
  983.       file_size := fileSize(f)
  984.     else
  985.       file_size := 0;
  986.     close(f);
  987.   end(*file_size*);
  988.  
  989. (* Utility functions for list generating routines: *)
  990.  
  991. function charStr(c : char; reserved : CClass) : String;
  992.   function octStr(c : char) : String;
  993.     (* return octal string representation of character c *)
  994.     begin
  995.       octStr := intStr(ord(c) div 64)+intStr((ord(c) mod 64) div 8)+
  996.                 intStr(ord(c) mod 8);
  997.     end(*octStr*);
  998.   begin
  999.     case c of
  1000.       #0..#7,      (* nonprintable characters *)
  1001.       #11..#31,
  1002.       #127..#255 : charStr := '\'+octStr(c);
  1003.       bs         : charStr := '\b';
  1004.       tab        : charStr := '\t';
  1005.       nl         : charStr := '\n';
  1006.       cr         : charStr := '\c';
  1007.       ff         : charStr := '\f';
  1008.       '\'        : charStr := '\\';
  1009.       else if c in reserved then
  1010.         charStr := '\'+c
  1011.       else
  1012.         charStr := c
  1013.     end
  1014.   end(*charStr*);
  1015.  
  1016. function singleQuoteStr(str : String) : String;
  1017.   var
  1018.     i : Integer;
  1019.     str1 : String;
  1020.   begin
  1021.     str1 := '';
  1022.     for i := 1 to length(str) do
  1023.       str1 := str1+charStr(str[i], ['''']);
  1024.     singleQuoteStr := ''''+str1+''''
  1025.   end(*singleQuoteStr*);
  1026.  
  1027. function doubleQuoteStr(str : String) : String;
  1028.   var
  1029.     i : Integer;
  1030.     str1 : String;
  1031.   begin
  1032.     str1 := '';
  1033.     for i := 1 to length(str) do
  1034.       str1 := str1+charStr(str[i], ['"']);
  1035.     doubleQuoteStr := '"'+str1+'"'
  1036.   end(*doubleQuoteStr*);
  1037.  
  1038. function cclassStr(cc : CClass) : String;
  1039.   const reserved : CClass = ['^','-',']'];
  1040.   var
  1041.     c1, c2 : Char;
  1042.     str : String;
  1043.   begin
  1044.     if cc=[#1..#255]-[nl] then
  1045.       cclassStr := '.'
  1046.     else
  1047.       begin
  1048.         str := '';
  1049.         if nchars(cc)>128 then
  1050.           begin
  1051.             str := '^';
  1052.             cc := [#0..#255]-cc;
  1053.           end;
  1054.         for c1:=#0 to #255 do
  1055.           if c1 in cc then
  1056.             begin
  1057.               c2 := c1;
  1058.               while (c2<#255) and (succ(c2) in cc) do
  1059.                 inc(c2);
  1060.               if c1=c2 then
  1061.                 str := str+charStr(c1, reserved)
  1062.               else if c2=succ(c1) then
  1063.                 str := str+charStr(c1, reserved)+charStr(c2, reserved)
  1064.               else
  1065.                 str := str+charStr(c1, reserved)+'-'+charStr(c2, reserved);
  1066.               c1 := c2
  1067.             end;
  1068.           cclassStr := '['+str+']'
  1069.       end
  1070.   end(*cclassStr*);
  1071.  
  1072. function cclassOrCharStr(cc : CClass) : String;
  1073.   var count : Integer;
  1074.       c, c1 : Char;
  1075.   begin
  1076.     count := 0;
  1077.     for c := #0 to #255 do
  1078.       if c in cc then
  1079.         begin
  1080.           c1 := c;
  1081.           inc(count);
  1082.           if count>1 then
  1083.             begin
  1084.               cclassOrCharStr := cclassStr(cc);
  1085.               exit;
  1086.             end;
  1087.         end;
  1088.     if count=1 then
  1089.       cclassOrCharStr := singleQuoteStr(c1)
  1090.     else
  1091.       cclassOrCharStr := '[]';
  1092.   end(*cclassOrCharStr*);
  1093.  
  1094. function regExprStr(r : RegExpr) : String;
  1095.   function unparseExpr(r : RegExpr) : String;
  1096.     var rule_no, pos : Integer;
  1097.         c : Char;
  1098.         str : StrPtr;
  1099.         cc : CClassPtr;
  1100.         r1, r2 : RegExpr;
  1101.     begin
  1102.       if is_epsExpr(r) then
  1103.         unparseExpr := ''
  1104.       else if is_markExpr(r, rule_no, pos) then
  1105.         unparseExpr := '#('+intStr(rule_no)+','+intStr(pos)+')'
  1106.       else if is_charExpr(r, c) then
  1107.         unparseExpr := charStr(c, [ '"','.','^','$','[',']','*','+','?',
  1108.                                     '{','}','|','(',')','/','<','>'])
  1109.       else if is_strExpr(r, str) then
  1110.         unparseExpr := doubleQuoteStr(str^)
  1111.       else if is_cclassExpr(r, cc) then
  1112.         unparseExpr := cclassStr(cc^)
  1113.       else if is_starExpr(r, r1) then
  1114.         unparseExpr := unparseExpr(r1)+'*'
  1115.       else if is_plusExpr(r, r1) then
  1116.         unparseExpr := unparseExpr(r1)+'+'
  1117.       else if is_optExpr(r, r1) then
  1118.         unparseExpr := unparseExpr(r1)+'?'
  1119.       else if is_catExpr(r, r1, r2) then
  1120.         unparseExpr := '('+unparseExpr(r1)+unparseExpr(r2)+')'
  1121.       else if is_altExpr(r, r1, r2) then
  1122.         unparseExpr := '('+unparseExpr(r1)+'|'+unparseExpr(r2)+')'
  1123.       else
  1124.         fatal('invalid expression');
  1125.     end(*unparseExpr*);
  1126.   begin
  1127.     regExprStr := unparseExpr(r);
  1128.   end(*regExprStr*);
  1129.  
  1130. end(*LexBase*).